﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Media.Effects;
using Windows.Media.MediaProperties;
using Windows.Foundation.Collections;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Graphics.Imaging;
using System.Runtime.InteropServices;

using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas;
using CommonLibrary;

namespace VideoEffectComponent {
    [ComImport]
    [Guid("5B0D3235-4DBA-4D44-865E-8F1D0E4FD04D")]
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
    unsafe interface IMemoryBufferByteAccess {
        void GetBuffer(out byte* buffer, out uint capacity);
    }

    public sealed class BaseVideoEffect : IBasicVideoEffect {

        public void Close(MediaEffectClosedReason reason) {
            // Dispose of effect resources
        }

        private int frameCount;
        public void DiscardQueuedFrames() {
            frameCount = 0;
        }

        public bool IsReadOnly { get { return false; } }
        public bool TimeIndependent { get { return true; } }
        public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Gpu; } }

        private IPropertySet configuration;
        public void SetProperties(IPropertySet configuration) {
            this.configuration = configuration;
            this.configuration.MapChanged += Configuration_MapChanged;
        }

        private void Configuration_MapChanged(IObservableMap<string, object> sender, IMapChangedEventArgs<string> @event) {
            _Subtitles = Subtitles;
        }

        private CanvasDevice canvasDevice;
        public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device) {
            canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device);
        }

        public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties {
            get {
                var encodingProperties = new VideoEncodingProperties();
                encodingProperties.Subtype = "ARGB32";
                return new List<VideoEncodingProperties>() { encodingProperties };
            }
        }


        public double BlurAmount {
            get {
                object val;
                if (configuration != null && configuration.TryGetValue("BlurAmount", out val)) {
                    return (double)val;
                }
                return 3;
            }
        }
        static List<Subtitle> _Subtitles = null;
        public dynamic Subtitles {
            get {
                object val;
                if (configuration != null && configuration.TryGetValue("Subtitles", out val)) {
                    return val;
                }
                return null;
            }
        }
        private Subtitle preSubtitle;
        public void ProcessFrame(ProcessVideoFrameContext context) {
            //frameCount++;
            using (CanvasBitmap inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(canvasDevice, context.InputFrame.Direct3DSurface))
            using (CanvasRenderTarget renderTarget = CanvasRenderTarget.CreateFromDirect3D11Surface(canvasDevice, context.OutputFrame.Direct3DSurface))
            using (CanvasDrawingSession ds = renderTarget.CreateDrawingSession()) {
                var gaussianBlurEffect = new GaussianBlurEffect {
                    Source = inputBitmap,
                    BlurAmount = (float)BlurAmount,
                    Optimization = EffectOptimization.Speed
                };

                ds.DrawImage(gaussianBlurEffect);
                TimeSpan? time = context.InputFrame.RelativeTime;
                if (time != null) {
                    if (preSubtitle != null && preSubtitle.BeginTime <= time && preSubtitle.EndTime > time) {
                        ds.DrawText(preSubtitle.Text, new System.Numerics.Vector2(300, 300), Windows.UI.Colors.Red);
                    } else {
                        foreach (var item in _Subtitles) {
                            if (item.BeginTime <= time && item.EndTime > time) {
                                preSubtitle = item;
                                ds.DrawText(item.Text, new System.Numerics.Vector2(300, 300), Windows.UI.Colors.Red);
                                break;
                            }
                        }
                    }
                }
            }
        }
    }
}
